#!/usr/bin/env coffee

import arch from '@/config/arch.mjs'

import platform from '@/config/platform.mjs'
import destroy from '../destroy.coffee'
import Win from '../win.coffee'
import {createHash} from 'crypto'
import {brotliDecompress as _brotliDecompress, createBrotliDecompress} from 'zlib'
import { promisify } from 'util'
brotliDecompress = promisify _brotliDecompress
import {unpack} from 'msgpackr'
import * as r64 from '../../lib/r64.mjs'
import {AUTO_UPDATE} from '../../config/site.coffee'
import {get as _get, get_stream} from '../net.coffee'
import {app} from 'electron'
import {encode} from 'urlsafe-base64'
import {createReadStream,createWriteStream,existsSync,mkdirSync} from 'fs'
import {rm,readdir,mkdir,copyFile,readFile} from 'fs/promises'
import {join,dirname} from 'path'
import config from '../config.coffee'
import {ROOT} from '../dir.coffee'
import PACKAGE_JSON,{package_json} from '../package_json.coffee'
import {ver_int} from '../ver.coffee'

export relaunch = =>
  app.relaunch()
  app.exit()

DIR_V = join ROOT, 'v'
mkdirSync DIR_V,recursive:true

HASH = 'sha512'

win = undefined
export x = =>
  destroy win
  win = undefined
  return

export show = =>
  x()
  win = Win.update(
    width:400
    height:500
    resizable: false
  )
  #win.setAlwaysOnTop(true,'screen-saver')
  return

get = (url)=>
  _get AUTO_UPDATE+url

###
bin2ver = (bin)=>
  n = 0
  r = []
  len = bin.length
  while n < len
    r.push bin.readUint16BE(n)
    n+=2
  r
###


hash = (fp)=>
  h = createHash HASH
  new Promise (resolve)=>
    createReadStream(
      fp
    ).on(
      'data'
      h.update.bind(h)
    ).on(
      'end'
      =>
        resolve h.digest()[..7]
        return
    )

已下载的最新版 = do =>
  {v} = config
  v and r64.decode(v)

export ver_now = =>
  PACKAGE_JSON().version

_platform = platform+'/'+arch+'/'

当前版 = ver_int ver_now()
VER_LATEST = 0

ver_latest_bin = =>
  now = r64.encode parseInt new Date()/1000
  url = _platform+'v?'+now
  try
    VER_LATEST = await get url
  catch err
    console.error '❌',url
  VER_LATEST

_update = (latest)=>
  if not latest
    latest = VER_LATEST or await ver_latest_bin()
  if not latest
    return
  最新版 = latest.readUintBE(0,6)
  if 当前版 >= 最新版
    return

  dir_name = r64.encode 最新版
  dir = join(DIR_V,dir_name)

  if existsSync join(dir,package_json)
    if 最新版 == 已下载的最新版
      return dir

  url = encode await get _platform+encode(latest)
  [dir_li,file_li,hash_li] = unpack(
    await brotliDecompress await get url
  )

  mk = (name)=>
    mkdir(
      join(dir,name)
      recursive:true
    )
  await Promise.all dir_li.map(mk)

  root = dirname(__dirname)

  for i,pos in file_li
    fp = join dir,i
    h = hash_li[pos]
    same = (file)=>
      Buffer.compare(h, await hash(file)) == 0

    if existsSync fp
      if await same fp
        continue

    await mk(dirname(i))

    local = join(root,i)
    if existsSync(local) and await same local
      await copyFile(local, fp)
      continue

    w = createWriteStream(
      fp
    )
    (await get_stream(AUTO_UPDATE+encode(h))).pipe(createBrotliDecompress()).pipe(w)
    await new Promise (resolve)=>
      w.on 'finish',resolve
      return
    if not await same(fp)
      return
  config.v = dir_name
  已下载的最新版 = 最新版
  return dir

export update_check = =>
  bin = await ver_latest_bin()
  if bin
    need_update =当前版 < bin.readUintBE(0,6)
    if need_update
      return bin
  return 0

daily_update =  =>
  if bin = await update_check()
    await update bin
  return

setInterval(
  daily_update
  86400000
)

RUNNING = UPDATE_PROMISE = UPDATE_PROMISE_RESOLVE = undefined

update_promise_init = =>
  UPDATE_PROMISE = new Promise (resolve)=>
    UPDATE_PROMISE_RESOLVE = resolve

update_promise_init()

export update_promise = =>
  UPDATE_PROMISE

export update = (args...)=>
  if not RUNNING
    RUNNING =  _update(...args).then(
      (dir)=>
        if dir
          UPDATE_PROMISE_RESOLVE([
            VER_LATEST
            JSON.parse(
              await readFile join(dir,package_json),'utf8'
            ).description
          ])
          update_promise_init()
        return
    ).finally =>
      RUNNING = false
      return
  return UPDATE_PROMISE


setTimeout(
  =>
    if existsSync DIR_V
      for i from await readdir(DIR_V, { withFileTypes: true })
        if i.isDirectory()
          {name} = i
          if r64.decode(name) < 当前版
            await rm(
              join(DIR_V,name)
              recursive: true
              force: true
            )

    day = parseInt new Date()/86400000
    if day == config.update_check
      return
    config.update_check = day
    await daily_update()
  15000
)
